        SUBT    > Sources.Ensure

; This file contains the routines for ensuring the existance of an object
; (file/directory). The object's names is assumed to be canonical when
; passed to these routines:

; EnsureObjectCommon
;  EnsureCanonicalObject
;   SimpleReadCatalogueInfo
;    AssessDestinationForPath
;     strcmp_forimagefilepath
;   OpenMultiFSFile
; AssessDestinationForPathTailForDirRead
; fscbscbTofscb

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; EnsureCanonicalObject
;
; In    r1 = path^ with absolutes resolved and no wildcards
;       r6 = special field^/scb^
;       fscb
;
; Out   r0 = Object type of end object
;       r1 = path^ for last path section
;       r2 = load address
;       r3 = execute address
;       r4 = object length
;       r5 = object attributes
;       r6 = special field^/scb^
;       fscb/ifscb
;
; This ensures the canonical object exists and returns its attributes.
; The path should be in canonical form.
;

EnsureCanonicalObject ENTRY "r7,r8,r9"
 [ debugensure
 DSTRING r6,"EnsureCanonicalObject ",cc
 DSTRING r1," "
 ]

        MOV     r7, r1
10
        LDRB    r0, [r7], #1
        BL      IsAbsolute
        BNE     %BT10
        SUB     r7, r7, #1      ; r7->1st absolute (eg $)

15
        BL      strlen
        ADD     r8, r1, r3      ; r8->nul terminator
        MOV     r9, #0

20
        ;
        ; Main loop start:
        ;
        ; Got a new start point - try the whole of the rest of the path with it
        ;
        ; registers:
        ; r1 -> next path part to try
        ; r7 -> start of interesting bit
        ; r8 -> terminator
        ; r9 = character to replace terminator after reading info

 [ debugensure
        DSTRING r1, "Trying "
        BVC     %FT01
        DLINE   "Urkh...VS before read catalogue"
01
 ]

        BL      SimpleReadCatalogueInfo
 [ debugensure
        DSTRING r1, "Resulting tail is "
        BVC     %FT01
        DLINE   "Urkh...error generated"
01
        DREG    r0, "r0=",cc
        DREG    r9, " r9=",cc
        DREG    r8, " for storage at "
 ]

        STRB    r9, [r8]

        EXIT    VS

        ; Return immediately on a non-nothing result on the whole thing
        TEQ     r9, #0
        BNE     %FT25
        TEQ     r0, #object_nothing
        EXITS   NE

25
        ; File or directory indicates whole thing doesn't exist - it's already been
        ; checked earlier and there's no partition to open in-between.
        TEQ     r0, #object_file
        TEQNE   r0, #object_directory
        MOVEQ   r0, #object_nothing
        EXITS   EQ

        TEQ     r0, #object_nothing
        BNE     %FT50

        ; It's an object_nothing - peel off one more leaf and have another go

        ; Ensure r7 is a sensible place to stop peeling back to
        CMP     r7, r1
        MOVLO   r7, r1

30
        CMP     r8, r7
        BLS     %FT40
        LDRB    r9, [r8, #-1]!
        TEQ     r9, #"."
        BNE     %BT30

        MOV     lr, #0
        STRB    lr, [r8]
        B       %BT20

40
        ; ran out of leaves to peel off - it doesn't exist
        MOV     r0, #object_nothing
        EXITS

50
        ; neither file nor directory, so it must be a MultiFS file - try openning it
        MOV     lr, #0
        STRB    lr, [r8]
 [ debugensure
        DSTRING r1, "Openning partition "
 ]
        BL      OpenMultiFSFile
        STRVCB  r9, [r8]
        BVC     %BT15
        EXIT


        LTORG

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; EnsureObjectCommon
;
; In    r1 = path^^
;       r3 = relativity indicator (0=>@; <>0=>%)
;       r6 = special field^^
;       fscb
;
; Out   r0 = Object type of end object
;       r1 = path^ for last path section (path^^ replaced as necessary)
;       r2 = load address
;       r3 = execute address
;       r4 = object length
;       r5 = object attributes
;       r6 = special field^/scb^ (special field^^ replaced as necessary)
;       fscb/ifscb
;
; The performs a similar function to AssessDestinationForPath, except it
; ensures the end object exists/doesn't exist.
;
EnsureObjectCommon ENTRY "r7"

 [ debugensure
 Push "r1,r6"
 LDR r1,[r1]
 LDR r6,[r6]
 DSTRING r6,"EnsureObjectCommon ",cc
 DSTRING r1," "
 Pull "r1,r6"
 ]
        BL      CanonicalisePath
        LDRVC   r1,[r1]
        LDRVC   r6,[r6]
        BLVC    EnsureCanonicalObject
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; OpenMultiFSFile
;
; In    r0 = object_file :OR: object_directory
;       r1 = fully canonical path^ for file
;       r2 = load address of file
;       r6 = special field^ or scb^
;       fscb/ifscb
;
; Out   File opened and attached in all the right places
;
OpenMultiFSFile ENTRY "r1,r2,r3,r4,r5,r7,scb"
        addr    r2, anull
        MOV     r5, #open_update
        MOV     r7, #open_update :OR: open_mustopen :OR: open_nodir :OR: open_nopath
        BL      DoTheOpen_Common
        EXIT    VS

        ; Convert handle to scb
        ADR     r14, streamtable
        LDR     scb, [r14, r0, LSL #2]  ; Get scb^

        ; Set 'image not ready' bit
        LDR     r14, scb_status
        ORR     r14, r14, #scb_partitionbad
        STR     r14, scb_status

        ; Convert filetype to ifscb
        LDR     r2, [sp, #1*4]
        BL      ExtractFileType
        BL      FileTypeToifscb
        STR     r1, scb_fscbForContents

        ; Attach scb to relevant image list
        LDRB    r14, [fscb, #fscb_info]
        TEQ     r14, #0
        LDRNE   r14, [fscb, #fscb_FirstImagescb]
        LDREQ   r14, [r6, #:INDEX:scb_ImageList]
        STR     r14, scb_NextImagescbInFile
        STRNE   scb, [fscb, #fscb_FirstImagescb]
        STREQ   scb, [r6, #:INDEX:scb_ImageList]

        ; Register this file with the ifs
        Push    "r0,fscb"
        MOV     fscb, r1
        MOV     r1, r0
        MOV     r0, #fsfunc_NewImage
        LDR     r14, scb_shift
        MOV     r2, #1
        MOV     r2, r2, ASL r14
        BL      CallFSFunc_Given
 [ debugensure
 DLINE "Return from NewImage"
 ]
        Pull    "r0,fscb"
 [ debugensure
        BVS     %FT01
        DREG    r1,"Just openned MultiFS handle, ifsHandle is "
01
 ]

        ; Mark image as OK now
        STRVC   r1, scb_ifsHandle
        LDRVC   r14, scb_status
        BICVC   r14, r14, #scb_partitionbad
        STRVC   r14, scb_status

        EXIT    VC

        ; The image filing system barfed - close the file and return error
        MOV     r1, r0
        CLRV
        BL      CloseThisFile
        SETV
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; strcmp_forimagefilepath
; Compares the user's path with the image path.
; If paths are exactly equal, then NE is returned.
; If paths are equal up to length of image file's path, and then
; the user's path continues .thing, then EQ is returned with
; r1 pointing past the .
; Examples:
; User          Image           Answer  Why
; a.b.c.d       e.f.g.h         NE      No relationship between the two
; a.b.c.d       a.b.c.e         NE      Image irrelevant to user's path
; a.b.c.d       a.b.c.d         NE      Image not of use when resolving to user object
; a.b.c.d.e     a.b.c.d         EQ,e    Image occurs on path to user's object
;
; In    r1 = canonical path supplied by user
;       r2 = image file's path
;
; Out   r1 = pointer to within path where comparison ended if EQ, otherwise
;               unchanged.
;       EQ, NE as appropriate
;
strcmp_forimagefilepath ENTRY "r1,r2,r3,r4"
        Internat_CaseConvertLoad r14,Lower
10      LDRB    r3, [r2], #1
        LDRB    r4, [r1], #1
        Internat_LowerCase r3, r14
        CMP     r3, #delete             ; Order, you git !
        CMPNE   r3, #space-1            ; Finished ?
        MOVLS   r3, #0
        Internat_LowerCase r4, r14
        CMP     r4, #delete             ; Order, you git !
        CMPNE   r4, #space-1            ; Finished ?
        MOVLS   r4, #0
        CMP     r3, r4                  ; Differ ?
        BNE     %FT20
        CMP     r3, #0
        BNE     %BT10
        TEQS    r1, #0                  ; Sets NE
        EXIT
20      TEQ     r3, #0
        EXIT    NE                      ; Exit with NE set if not at end of image path
        TEQ     r4, #"."
        STREQ   r1, [sp, #0*4]
        EXIT                            ; Exit with EQ/NE depending on presence of a . in user path

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; AssessDestinationForPath
;
; In    r1 = canonical path^
;       r6 = special field^/scb^
;       fscb
;
; Out   r1 = path^ to pass to ifscb
;       r6 = unchanged or set to scb
;       fscb left unchanged or set to ifscb
;       flags preserved
;
; This routine scans the fscb table for this fscb and finds the fscb
; relevant for this path. Note that this routine does not ensure that
; the fscb is correct as it may be the case that a deeper nesting of
; fscbs is required.

AssessDestinationForPath ENTRY "r2,r3,scb"

 [ debugensure
 DSTRING r1, "Assessing destination for "
 ]

        ; If it's a MultiFS set ourselves up and branch to the MutliFS handling
        LDRB    r14, [fscb, #fscb_info]
        TEQ     r14, #0
        BNE     %FT05
        MOV     scb, r6
        B       %FT30

05
        ; Non-MultiFS handling...
        MOV     r3, r1                          ; Hold original path

        ; Start along chain of image scbs for this fscb
        ADD     scb, fscb, #fscb_FirstImagescb - :INDEX:scb_NextImagescbInFile
10
        LDR     scb, scb_NextImagescbInFile
        TEQ     scb, #Nowt
        MOVEQ   r1, r3
        EXITS   EQ

        LDR     r1, scb_special
        MOV     r2, r6
        BL      strcmp
        BNE     %BT10
        LDR     r2, scb_path
 [ debugensure
 DSTRING r2, "Checking path against "
 ]
        MOV     r1, r3
        BL      strcmp_forimagefilepath
        BNE     %BT10

        ; It's a match!
 [ debugensure
 DLINE "It's a match!"
 ]

20
        ; Get fscb for accessing the contents of this image file
        ; and the image filing system's handle for this
        LDR     fscb, scb_fscbForContents
        MOV     r6, scb

30
        ; MultiFS handling starts here with fscb, scb and r6 set up.

        ; Save the good new start of path
        MOV     r3, r1

        ; Now check for images in this image...
        ADD     scb, scb, # :INDEX:scb_ImageList - :INDEX:scb_NextImagescbInFile
40
        MOV     r1, r3                          ; Back to the start of this path
        LDR     scb, scb_NextImagescbInFile
        TEQ     scb, #Nowt
        EXITS   EQ                              ; No more Russian dolls!

        LDR     r2, scb_path
 [ debugensure
 DSTRING r2, "Checking path against "
 ]
        BL      strcmp_forimagefilepath
        BNE     %BT40

 [ debugensure
 DLINE "It's a match!"
 ]

        ; It's a match (again!)
        B       %BT20                           ; Go round again


; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; AssessDestinationForPathTailForDirRead
;
; In    r0 = object type of 'directory'
;       r1 = canonical path^
;       r2 = load address of file
;       r6 = special field^/scb^
;       fscb
;
; Out   r1 = path^ to pass to ifscb (a nul string)
;       r6 = set to scb^ of opened MultiFS file
;       fscb set to ifscb
;
; This routine scans the fscb table for this fscb and finds the fscb
; relevant for this path. Note that this routine does not ensure that
; the fscb is correct as it may be the case that a deeper nesting of
; fscbs is required.

AssessDestinationForPathTailForDirRead ENTRY "r2,r3,scb"
 [ debugensure
 DSTRING r1, "Assessing destination for dir read on "
 ]
        TEQ     r0, #object_file :OR: object_directory
        EXIT    NE

        MOV     r3, r1                          ; Hold original path

05
        ; If it's a MultiFS set ourselves up and branch to the MutliFS handling
        LDRB    r14, [fscb, #fscb_info]
        TEQ     r14, #0
        BEQ     %FT30

        ; Non-MultiFS handling...

        ; Start along chain of image scbs for this fscb
        ADD     scb, fscb, #fscb_FirstImagescb - :INDEX:scb_NextImagescbInFile
10
        LDR     scb, scb_NextImagescbInFile
        TEQ     scb, #Nowt
        BEQ     %FT50

        LDR     r1, scb_special
        MOV     r2, r6
        BL      strcmp
        BNE     %BT10
        LDR     r2, scb_path
        MOV     r1, r3
 [ debugensure
 DSTRING r1, "Checking path ",cc
 DSTRING r2," against "
 ]
        BL      strcmp
        BNE     %BT10

        ; It's a match!

20
 [ debugensure
 DLINE "It's a match!"
 ]
        ; Get fscb for accessing the contents of this image file
        ; and the image filing system's handle for this
        LDR     fscb, scb_fscbForContents
        MOV     r6, scb
        MOV     r3, r1
        BL      strlen_accumulate
        MOV     r1, r3
        EXIT

30
        ; MultiFS handling starts here with fscb, r6 set up.
        MOV     scb, r6

        ; Now check for images in this image...
        ADD     scb, scb, # :INDEX:scb_ImageList - :INDEX:scb_NextImagescbInFile
40
        LDR     scb, scb_NextImagescbInFile
        TEQ     scb, #Nowt
        BEQ     %FT50

        LDR     r2, scb_path
        MOV     r1, r3
 [ debugensure
 DSTRING r1, "Checking path ",cc
 DSTRING r2," against "
 ]
        BL      strcmp
        BNE     %BT40

        ; It's a match
        B       %BT20

50
        ; No match - open the MultiFS file
        ; Once open, re-find using above mechanism
        LDR     r2, [sp, #0*4]
        BL      OpenMultiFSFile
        BVC     %BT05
        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; SimpleReadCatalogueInfo
;
; In    r1 = path^ to perform action on
;       r6 = special field^/scb^
;       fscb for path
;
; Out   r0 = object type of result (0, 1, 2 or 3)
;       r1 = path^ used
;       r2 = load address
;       r3 = execute address
;       r4 = object length
;       r5 = object attributes
;       r6 = special field^/scb^ used
;       fscb = fscb/ifscb used
;
; This checks for the path being a MultiFS path and uses that first.
; The results are adjusted for MultiFSness.
;
SimpleReadCatalogueInfo ENTRY

 [ debugensure
 DSTRING r6,"SimpleReadCatalogueInfo(#",cc
 DSTRING r1,":",cc
 DLINE ")"
 ]

        ; Get ifscb and file handle as necessary
        BL      AssessDestinationForPath
        MOV     r0, #fsfile_ReadInfo
        BL      CallFSFile_Given

        ; If all OK, then adjust the objecttype
        ADRVC   r14, fileblock_base
        LDMVCIA r14, {r2-r5}
        BL      ComplexAdjustObjectTypeReMultiFS

 [ debugensure
 DREG r0, "....=(Tp=",cc
 DREG r2, ",Ld=",cc
 DREG r3, ",Ex=",cc
 DREG r4, ",Ln=",cc
 DREG r5, ",At=",cc
 DLINE ")"
 ]

        EXIT

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; fscbscbTofscb
;
; In    r6 = special field or scb^
;       fscb
;
; Out   r2 = fscb of the root non-MultiFS
;
fscbscbTofscb ENTRY "r6"
 [ debugensure
 DREG fscb,"fscbscbTofscb(",cc
 DREG r6,",",cc
 DLINE ")",cc
 ]
        MOV     r2, fscb
10
        LDRB    r14, [r2, #fscb_info]
        TEQ     r14, #0
 [ debugensure
 BEQ %FT01
 DREG r2,"="
01
 ]
        EXIT    NE
        LDR     r2, [r6, #:INDEX:scb_fscb]
        LDR     r6, [r6, #:INDEX:scb_special]
 [ debugensure
 DREG r2,"->(",cc
 DREG r6,",",cc
 DLINE ")",cc
 ]
        B       %BT10

        END
